package com.united.ucts.modules.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.digest.BCrypt;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.github.pagehelper.PageHelper;
import com.united.frame.common.constant.AuthConstant;
import com.united.frame.common.constant.GlobalConstant;
import com.united.frame.common.enums.YesOrNoEnum;
import com.united.frame.common.exception.UnitedException;
import com.united.frame.common.module.result.Result;
import com.united.frame.common.module.result.ResultCodeEnum;
import com.united.frame.common.module.service.impl.BaseServiceImpl;
import com.united.frame.common.util.IpUtil;
import com.united.frame.plugin.security.CurrUser;
import com.united.frame.plugin.security.Oauth2Token;
import com.united.ucts.common.exception.UctsException;
import com.united.ucts.common.plugin.feign.AuthService;
import com.united.ucts.modules.system.mybatis.mapper.AdminLoginLogMapper;
import com.united.ucts.modules.system.mybatis.mapper.AdminMapper;
import com.united.ucts.modules.system.mybatis.mapper.AdminRoleRelationMapper;
import com.united.ucts.modules.system.pojo.dto.AdminDto;
import com.united.ucts.modules.system.pojo.dto.AdminParamDto;
import com.united.ucts.modules.system.pojo.dto.AdminPasswordUpdateParamDto;
import com.united.ucts.modules.system.pojo.po.*;
import com.united.ucts.modules.system.service.AdminCacheService;
import com.united.ucts.modules.system.service.AdminService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * UmsAdminService实现类
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class AdminServiceImpl extends BaseServiceImpl<AdminMapper, Admin> implements AdminService {
    private final AdminRoleRelationMapper adminRoleRelationMapper;
    private final AdminLoginLogMapper loginLogMapper;
    private final AuthService authService;
    private final AdminCacheService adminCacheService;
    private final HttpServletRequest request;

    /**
     * 根据前端的管理员新增/注册信息,对用户注册信息进行注册处理
     *
     * @param param 用户注册/新增请求参数
     * @return 注册成功后结果
     */
    @Override
    public Admin register(AdminParamDto param) {
        // 先判断本次需要创建的对应用户名的用户信息是否存在
        Admin existAdmin = this.selectByUserName(param.getUserName());
        if (Objects.nonNull(existAdmin)) {
            return null;
        }

        Admin admin = new Admin();
        BeanUtils.copyProperties(param, admin);
        admin.setUsername(param.getUserName())
                // 将密码进行加密操作
                .setPassword(BCrypt.hashpw(admin.getPassword()))
                .setStatus(YesOrNoEnum.YES.getFlag());
        this.save(admin);
        return admin;
    }

    /**
     * 删除指定用户
     *
     * @param id 需要删除的管理员用户ID
     * @return 删除结果
     */
    @Override
    public Boolean delete(String id) {
        // 先逻辑删除相应的用户
        boolean result = this.removeById(id);

        // 删除成功后,更新用户缓存
        if (result) {
            adminCacheService.delAdmin(id);
        }
        return result;
    }

    /**
     * 修改指定用户信息
     *
     * @param id    需要进行更新处理得管理员用户ID
     * @param admin 具体更改信息对象
     * @return 更改结果
     */
    @Override
    public Boolean update(String id, Admin admin) {

        // 先根据ID获取相应管理员详情
        Admin rawAdmin = this.getById(id);
        if (rawAdmin.getPassword().equals(admin.getPassword())) {
            // 与原加密密码相同的不需要修改
            admin.setPassword(null);
        } else {
            // 与原加密密码不同的需要加密修改
            if (StrUtil.isEmpty(admin.getPassword())) {
                admin.setPassword(null);
            } else {
                admin.setPassword(BCrypt.hashpw(admin.getPassword()));
            }
        }

        admin.setId(id);
        boolean result = this.updateById(admin);
        // 更新成功后,更新用户缓存
        if (result) {
            adminCacheService.delAdmin(id);
        }
        return result;
    }

    /**
     * 根据用户ID获取该用户详情信息
     *
     * @param id 用户ID
     * @return 用户详情信息
     */
    @Override
    public Admin getItem(String id) {
        return this.getById(id);
    }

    /**
     * 根据用户名或昵称分页查询用户
     *
     * @param pageNum  当前页数
     * @param pageSize 每页大小
     * @param keyword  查询关键字(用户名或昵称)
     * @return 分页结果
     */
    @Override
    public List<AdminDto> pageBy(Integer pageNum, Integer pageSize, String keyword) {

        // 分页查询获取相应分页数据
        PageHelper.startPage(pageNum, pageSize);
        List<Admin> admins = this.selectByUserNameOrNickName(keyword);
        if (CollUtil.isEmpty(admins)) {
            return Collections.emptyList();
        }

        // 将PO对象转换成VO对象
        AtomicReference<AdminDto> admin = new AtomicReference<>();
        return admins.stream().map(e -> {
            admin.set(BeanUtil.copyProperties(e, AdminDto.class));
            admin.get().setUserName(e.getUsername());

            return admin.get();
        }).collect(Collectors.toList());

    }


    @Override
    public int updateRole(String adminId, List<String> roleIds) {
        int count = roleIds == null ? 0 : roleIds.size();
        // 先删除原来的关系
        LambdaQueryWrapper<AdminRoleRelation> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(AdminRoleRelation::getAdminId, adminId);
        adminRoleRelationMapper.delete(queryWrapper);

        // 建立新关系
        if (!CollectionUtils.isEmpty(roleIds)) {
            List<AdminRoleRelation> list = new ArrayList<>();
            for (String roleId : roleIds) {
                AdminRoleRelation roleRelation = new AdminRoleRelation();
                roleRelation.setAdminId(adminId);
                roleRelation.setRoleId(roleId);
                list.add(roleRelation);
            }
            adminRoleRelationMapper.insertList(list);
        }
        return count;
    }

    @Override
    public List<Role> getRoleList(String adminId) {
        return adminRoleRelationMapper.getRoleList(adminId);
    }

    @Override
    public List<Resource> getResourceList(String adminId) {
        return adminRoleRelationMapper.getResourceList(adminId);
    }

    @Override
    public int updatePassword(AdminPasswordUpdateParamDto param) {
        if (StrUtil.isEmpty(param.getUsername())
                || StrUtil.isEmpty(param.getOldPassword())
                || StrUtil.isEmpty(param.getNewPassword())) {
            return -1;
        }

        // 根据用户名获取相应账户列表
        Admin admin = this.selectByUserName(param.getUsername());
        if (Objects.isNull(admin)) {
            return -2;
        }

        if (!BCrypt.checkpw(param.getOldPassword(), admin.getPassword())) {
            return -3;
        }
        admin.setPassword(BCrypt.hashpw(param.getNewPassword()));
        baseMapper.updateById(admin);
        adminCacheService.delAdmin(admin.getId());
        return 1;
    }

    @Override
    public Result<Oauth2Token> login(String username, String password) {
        if (StrUtil.isEmpty(username) || StrUtil.isEmpty(password)) {
            throw new UctsException("用户名或密码不能为空!");
        }
        Map<String, String> params = new HashMap<>(5);
        params.put("client_id", AuthConstant.ADMIN_CLIENT_ID);
        params.put("client_secret", "123456");
        params.put("grant_type", "password");
        params.put("username", username);
        params.put("password", password);
        Result<Oauth2Token> restResult = authService.getAccessToken(params);
        if (ResultCodeEnum.SUCCESS.getCode().equals(restResult.getCode()) && restResult.getData() != null) {
//            updateLoginTimeByUsername(username);
            insertLoginLog(username);
        }
        return restResult;
    }

    /**
     * 添加登录记录
     *
     * @param username 用户名
     */
    private void insertLoginLog(String username) {
        Admin admin = getAdminByUsername(username);
        if (admin == null) {
            return;
        }

        AdminLoginLog loginLog = new AdminLoginLog();
        loginLog.setAdminId(admin.getId())
                .setIp(IpUtil.getIpAddr())
                .setCreateUser(admin.getCreateUser());
        loginLogMapper.insert(loginLog);
    }

    /**
     * 根据用户名修改登录时间
     */
    private void updateLoginTimeByUsername(String username) {
        LambdaUpdateWrapper<Admin> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(Admin::getLoginTime, LocalDateTime.now())
                .eq(Admin::getUsername, username);
        this.update(updateWrapper);
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username 用户账户名
     * @return 后台用户信息
     */
    @Override
    public Admin getAdminByUsername(String username) {
        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Admin::getUsername, username);
        List<Admin> admins = this.list(queryWrapper);
        if (CollUtil.isNotEmpty(admins)) {
            return admins.get(0);
        }
        return null;
    }

    /**
     * 根据用户名获取用户信息
     *
     * @param username 用户账户名
     * @return 当前登录用户信息
     */
    @Override
    public CurrUser loadUserByUsername(String username) {
        // 获取用户信息
        Admin admin = getAdminByUsername(username);
        if (Objects.isNull(admin)) {
            throw new UnitedException("USERNAME NOT SUPPORT");
        }

        List<Role> roles = getRoleList(admin.getId());
        CurrUser user = new CurrUser();
        BeanUtils.copyProperties(admin, user);
        user.setEnable(YesOrNoEnum.YES.getFlag().compareTo(admin.getStatus()) == 0);
        if (CollUtil.isNotEmpty(roles)) {
            List<String> roleNames =
                    roles.stream()
                            .map(item -> item.getId() + GlobalConstant.CHAR_UNDERLIN_SPLIT + item.getName())
                            .collect(Collectors.toList());
            user.setRoles(roleNames);
        }
        return user;
    }

    @Override
    public Admin getCurrentAdmin() {
        String userStr = request.getHeader(AuthConstant.USER_TOKEN_HEADER);
        if (StrUtil.isEmpty(userStr)) {
            throw new UctsException(ResultCodeEnum.UNAUTHORIZED);
        }
        CurrUser userDto = JSONUtil.toBean(userStr, CurrUser.class);
        Admin admin = adminCacheService.getAdmin(userDto.getId());
        if (admin != null) {
            return admin;
        } else {
            admin = baseMapper.selectById(userDto.getId());
            adminCacheService.setAdmin(admin);
            return admin;
        }
    }

    /**
     * 根据管理员名称获取相应管理员信息
     *
     * @param userName 管理员名称
     * @return 匹配的管理员列表
     */
    private Admin selectByUserName(String userName) {
        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Admin::getUsername, userName);
        return this.getOne(queryWrapper);
    }

    /**
     * 根据用户名或者昵称进行模糊查询获取相应条件下的用户信息
     *
     * @param userName 用户名/昵称
     * @return 用户信息
     */
    private List<Admin> selectByUserNameOrNickName(String userName) {
        LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(Admin::getUsername, userName)
                .or()
                .like(Admin::getNickName, userName);
        return this.list(queryWrapper);
    }
}